package com.zj.study.pojo.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;

/**
 * <p>
 *   树形结构类，定义了如下操作
 *  <ui>
 *    <li>返回根节点</li>
 *    <li>返回最后添加节点</li>
 *    <li>判断是否具有子节点</li>
 *    <li>添加节点</li>
 *    <li>移动节点到其他节点下</li>
 *    <li>获取对应nodeType的所有节点或实体</li>
 *    <li>根据实体获取节点</li>
 *    <li>获取父节点</li>
 *    <li>转化为map结构</li>
 *  </ui>
 * <p/>
 *
 * @author 赵赳
 * @since 2021/12/14 10:02
 */
public class BeanTree {

  /**根节点*/
  private BeanTreeNode root;

  /**
   * 最新添加的节点
   */
  private BeanTreeNode currentNode;


  /**
   * @return the currentNode
   */
  public BeanTreeNode getCurrentNode() {
    return currentNode;
  }

  /**
   * @return the root
   */
  public BeanTreeNode getRoot() {
    return root;
  }

  /**
   * 判断节点是否有子节点.
   * @param node 要判断的节点
   * @return true or false
   */
  public boolean haveChild(BeanTreeNode node) {
    return CollectionUtils.isEmpty(node.getChildNodes());
  }

  /**
   * 在父节点上面添加节点，并返回天添加的节点.
   * @param parentNode 父节点
   * @param bean 要添加的bean
   * @param nodeType 节点类型
   * @return 返回包含bean的节点
   */
  public BeanTreeNode addNode(BeanTreeNode parentNode, Object bean, String nodeType) {
    BeanTreeNode node;
    if (bean == null) {
      return null;
    }
    //如果没有父节点说明为root根节点
    if (parentNode == null) {
      node = root = new BeanTreeNode(null, nodeType, bean);
    } else {
      //创建子节点，并添加到父节点上
      node = new BeanTreeNode(parentNode, nodeType, bean);
      parentNode.getChildNodes().add(node);
    }
    currentNode = node;
    return node;
  }

  /**
   * 将当期bean-sBean,以及sBean下的子Bean，挂到dBean下
   * @param sBean 源Bean
   * @param dBean 目的父Bean
   */
  public void removeTo(Object sBean, Object dBean) {
    BeanTreeNode sNode = getNodeByBean(sBean);
    BeanTreeNode dNode = getNodeByBean(dBean);
    removeTo(sNode, dNode);
  }

  /**
   * 将当期node-sNode,以及sNode下的子Node，挂到dNode下
   * @param sNode 源node
   * @param dNode 目的父node
   */
  public void removeTo(BeanTreeNode sNode, BeanTreeNode dNode) {
    //从当前父节点移除sNode
    sNode.getParentNode().getChildNodes().remove(sNode);
    //将sNode移到dNode下
    dNode.getChildNodes().add(sNode);
    //修改sNode的父Id和父节点
    sNode.setPid(dNode.getId());
    sNode.setParentNode(dNode);
  }

  /**
   * 获取父bean.
   * @param bean 子bean
   * @return 返回父bean
   */
  public Object getParentBean(Object bean) {
    return getNodeByBean(bean).getParentNode().getBean();
  }

  /**
   * 根据传入的bean获取bean下面对应类型的子bean.
   * @param bean 当前bean
   * @param nodeType 节点类型
   * @return 子bean的集合
   */
  public List<Object> getBeanListByBeanAndNodeType(Object bean, String nodeType) {
    BeanTreeNode node = getNodeByBean(bean);
    return getBeanListByNodeType(node, nodeType);
  }

  /**
   * 根据传入的bean获取包含bean的Node节点
   * @param node 当前node
   * @param bean 要查找的bean
   * @return node节点
   */
  public BeanTreeNode getNodeByBean(BeanTreeNode node, Object bean) {
    BeanTreeNode resultNode = null;
    if (node.getBean().equals(bean)) {
      resultNode = node;
      return resultNode;
    } else {
      for (BeanTreeNode tempNode : node.getChildNodes()) {
        resultNode = getNodeByBean(tempNode, bean);
        if (resultNode != null) {
          break;
        }
      }
    }
    return resultNode;
  }

  /**
   * 根据传入的bean获取root节点下包含bean的Node节点
   * @param bean 要查找的bean
   * @return node节点
   */
  public BeanTreeNode getNodeByBean(Object bean) {
    return getNodeByBean(root, bean);
  }

  /**
   * 根据节点类型返回当前节点下对应节点类型的bean的list集合.
   * 默认如果当前节点满足类型，那么当前节点不会存在相同类型的子节点
   * @param node 当前节点
   * @param nodeType 节点类型
   * @return
   */
  @SuppressWarnings("unchecked")
  public <T> List<T> getBeanListByNodeType(BeanTreeNode node, String nodeType) {
    List<T> beanList = new ArrayList<T>();
    if (node.getNodeType().equals(nodeType)) {
      beanList.add((T)node.getBean());
    } else {
      for (BeanTreeNode tempNode : node.getChildNodes()) {
        beanList.addAll((Collection<? extends T>) getBeanListByNodeType(tempNode, nodeType));
      }
    }
    return beanList;
  }
  /**
   * 根据节点类型返回根节点下对应节点类型的bean的list集合.
   * @param nodeType 节点类型
   * @return
   */
  public <T> List<T> getBeanListByNodeType(String nodeType) {
    return getBeanListByNodeType(root, nodeType);
  }

  /**
   * 从root节点开始获取对应nodeType的node.
   * @param nodeType 节点类型
   * @return nodeType类型的节点集合
   */
  public List<BeanTreeNode> getNodeListByNodeType(String nodeType) {
    return getNodeListByNodeType(root, nodeType);
  }

  /**
   * 从node节点开始获取对应nodeType的node.
   * @param node node节点
   * @param nodeType 节点类型
   * @return nodeType类型的节点集合
   */
  public List<BeanTreeNode> getNodeListByNodeType(BeanTreeNode node, String nodeType) {
    List<BeanTreeNode> nodeList = new ArrayList<BeanTreeNode>();
    if(node==null){
      return nodeList;
    }
    if (nodeType.equals(node.getNodeType())) {
      nodeList.add(node);
    } else {
      for (BeanTreeNode tempNode : node.getChildNodes()) {
        nodeList.addAll(getNodeListByNodeType(tempNode, nodeType));
      }
    }

    return nodeList;
  }

  /**
   * 将树形结构转化为map.
   * @return
   */
  public Map<String, List<Object>> toMap() {
    return toMap(root);
  }

  public Map<Object, Map<Object,List<Object>>> toTreeMap1() {
    return toTreeMap2(root);
  }

  public Map<Object, Map<Object,List<Object>>> toTreeMap2(BeanTreeNode node) {
    Map<Object, Map<Object,List<Object>>> map = new HashMap<>();
    toTreeMap3(node, map);
    return map;
  }



  /**
   * 将对应节点及其子节点转化为map.
   * @param node 树节点
   * @return 转化后的map
   */
  public Map<String, List<Object>> toMap(BeanTreeNode node) {
    Map<String, List<Object>> map = new HashMap<>();
    toMap(node, map);
    return map;
  }


  /**
   * 根据传入的nodeType删除对应的节点以及其所有子节点.
   * @param nodeType
   */
  public void delNodeByNodeType(String nodeType) {
    delNodeByNodeType(root, nodeType);
  }

  /**
   * 删除node节点下，类型为nodeType的节点和所有子节点
   * @param node
   * @param nodeType
   */
  public void delNodeByNodeType(BeanTreeNode node, String nodeType) {
    List<BeanTreeNode> nodeList = getNodeListByNodeType(node, nodeType);
    for (BeanTreeNode beanTreeNode : nodeList) {
      beanTreeNode.getParentNode().getChildNodes().remove(beanTreeNode);
    }
  }

  /**
   * 从树结构里面删除bean和相关node.
   * @param bean bean
   */
  public void delNodeByBean(Object bean) {
    BeanTreeNode node = getNodeByBean(bean);
    BeanTreeNode parentNode = node.getParentNode();
    List<BeanTreeNode> childNodes = parentNode.getChildNodes();
    childNodes.removeIf(beanTreeNode -> node == beanTreeNode);
  }


  /**
   * 根据class返回对应的beanList.
   * @param cls class
   * @return beanList
   */
  public <T> List<Object> getBeanListByClass(Class<T> cls) {
    return getBeanListByClass(root, cls);
  }

  /**
   * 根据class返回对应的beanList.
   * @param node 节点
   * @param cls class
   * @return beanList
   */
  public <T> List<Object> getBeanListByClass(BeanTreeNode node, Class<T> cls) {
    List<Object> beanList = new ArrayList<Object>();
    Object bean = node.getBean();
    if (cls.isAssignableFrom(bean.getClass())) {
      beanList.add(bean);
    }
    List<BeanTreeNode> childNodes = node.getChildNodes();
    for (BeanTreeNode beanTreeNode : childNodes) {
      beanList.addAll(getBeanListByClass(beanTreeNode, cls));
    }
    return beanList;
  }


  /**
   * 将对应节点及其子节点转化为map.
   * @param node 树节点
   * @param map 用来保存结果的map
   */
  private void toMap(BeanTreeNode node, Map<String, List<Object>> map) {
    String key = node.getNodeType();
    Object bean = node.getBean();
    if (map.containsKey(key)) {
      map.get(key).add(bean);
    } else {
      List<Object> list = new ArrayList<Object>();
      list.add(bean);
      map.put(key, list);
    }
    for (BeanTreeNode tempNode : node.getChildNodes()) {
      toMap(tempNode, map);
    }
  }

  /**
   * 将对应节点及其子节点转化为map.
   * @param node 树节点
   * @param map 用来保存结果的map
   */
  private void toTreeMap3(BeanTreeNode node, Map<Object, Map<Object,List<Object>>> map) {
    Map<Object, List<Object>> nodeMap = new HashMap<>();
    // 父节点 key root
    //String key = node.getNodeType();
    //  rootBean
    Object rootBean = node.getBean();
    var childNodes = node.getChildNodes();
    //List<Object> parenList = new ArrayList<>();
    map.put(rootBean,nodeMap);
    for (BeanTreeNode childNode : childNodes) {
      var parentBean = childNode.getBean();
      List<Object> childList = new ArrayList<>();
      nodeMap.put(parentBean, childList);
      //parenList.add(parentBean);
      var childNodes1 = childNode.getChildNodes();
      // 子节点
      for (BeanTreeNode beanTreeNode : childNodes1) {
        var childBean = beanTreeNode.getBean();
        childList.add(childBean);
      }
    }
  }


}
